/*
    Buffered BYTE oriented FIFO

	Uses providers/consumer model.  When an interrupt
	drives the consumer/provider side use the interrupt calls

	The fifo needs to be both declared and initialized.
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include "BuffFifo.h"

typedef uint8_t BOOL;

// Since there is only one process modifying each side of the
// FIFO, I am pretty sure critical sections are not needed.
// The only race is if the out pointer changes after the load
// and before the test. But this is not a race that will cause
// fifo corruption.

int16_t BuffPutFifo(psBufFifo p, uint8_t c)
{
	uint8_t t = p->in+1;

	if (t >= p->size)
		t = 0;

	if (t == p->out)	// isFull()
	{
		printf("BF 0x%X %d %d\r\n",p,p->in,p->out);
		return FIFO_ERR;
	}

	p->buf[p->in] = c;
	p->in = t;

	return FIFO_OK;
}

int16_t BuffPullFifo(psBufFifo p)
{
	if (p->in == p->out)	// isEmpty()
		return FIFO_ERR;
	uint16_t c = p->buf[p->out];
	uint8_t t = p->out+1;
	if (t >= p->size)
		t = 0;
	p->out = t;

	return c;
}

void BuffWaitPutFifo(psBufFifo p, uint8_t c)
{
	while (BuffPutFifo(p, c) == FIFO_ERR);
		
}

int16_t BuffWaitPullFifo(psBufFifo p)
{
	int16_t c;
	while ((c = BuffPullFifo(p)) == FIFO_ERR);
		
	return c;
}

void BuffFlushFifo(psBufFifo p)
{
	p->in = 0;
	p->out = 0;
}

// Return next character to be removed (without removing it)

int16_t BuffPeekFifo(psBufFifo p)
{
	if (p->in == p->out)
		return FIFO_ERR;
	else
		return p->buf[p->out];
}

// Return size of FIFO (difference between in & out

int16_t BuffStatFifo(psBufFifo p)
{
	uint8_t sreg = SREG;
	cli();
	int16_t c = (uint16_t)p->in - (uint16_t)p->out;
	SREG = sreg;
	if (c < 0)
		c += p->size;
	return c;
}

